﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Drawing;

namespace MortEdit
{
    internal class SyntaxHighlighting
    {
        private bool regexUpdated = false;
        private Regex keywordsRegexp;
        private Regex quotesRegexp;
        private Regex numbersRegexp;
        private Regex commentsRegexp;
        private Regex stringsRegexp;

        // podświetl całą linię
        public void HightlightCurrentLine(RichTextBoxExtended richTextBoxExtended)
        {
            if (regexUpdated == false)
            {
                RegexUpdate(richTextBoxExtended);
            }

            string line = RichTextBoxExtendedHelper.CurrentLineText(richTextBoxExtended);
            int lineStart = RichTextBoxExtendedHelper.CurrentLineStartIndex(richTextBoxExtended);

            ProcessLine(richTextBoxExtended, line, lineStart);
        }

        // Podświetla tylko zaznaczenie
        public void HighlightSelection(RichTextBoxExtended richTextBoxExtended, int SelectionStart, int SelectionLength)
        {
            // Jeśli wyrażenia regularne nie były zaktualizowane -> zrób to
            if (regexUpdated == false)
            {
                RegexUpdate(richTextBoxExtended);
            }

            ProcessSelection(richTextBoxExtended, SelectionStart, SelectionLength);
        }

        // Podświetla syćko
        public void HightlightAllLines(RichTextBoxExtended richTextBoxExtended)
        {
            if (regexUpdated == false)
            {
                RegexUpdate(richTextBoxExtended);
            }

            ProcessAllLines(richTextBoxExtended);
        }

        // aktualizacja regexpów
        public void RegexUpdate(RichTextBoxExtended richTextBoxExtended)
        {
            string keywords = string.Empty;
            string comments = string.Empty;

            // pętla dodaje wszystkie elementy RichTextBoxExtended.KeywordList 
            // do regexpa keywordsRegexp
            for (int i = 0; i < richTextBoxExtended.KeywordsList.Count; i++)
            {
                string strKeyword = richTextBoxExtended.KeywordsList[i];

                if (i == richTextBoxExtended.KeywordsList.Count - 1)
                    keywords += "\\b" + strKeyword + "\\b";
                else
                    keywords += "\\b" + strKeyword + "\\b|";
            }

            // dodaje elementy RichTextBoxExtended.CommentsCharList do
            // regexpa commentsRegexp
            for (int i = 0; i < richTextBoxExtended.commentsCharList.Count; i++)
            {
                string strComments = richTextBoxExtended.commentsCharList[i];

                if (i == richTextBoxExtended.commentsCharList.Count - 1)
                    comments += "" + strComments + ".*$";
                else
                    comments += "" + strComments + ".*$|";
            }

            // utworzenie obiektów typu Regex i wprowadzenie doń słów kluczowych i takich tam
            keywordsRegexp = new Regex(keywords, RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase);
            commentsRegexp = new Regex(comments, RegexOptions.Compiled | RegexOptions.Multiline);
            quotesRegexp = new Regex("\".*\"", RegexOptions.Compiled | RegexOptions.Multiline);
            numbersRegexp = new Regex("[0-9_]+", RegexOptions.Compiled | RegexOptions.Multiline);
            stringsRegexp = new Regex("\"[^\"\\\\\\r\\n]*(?:\\\\.[^\"\\\\\\r\\n]*)*\"", RegexOptions.Compiled | RegexOptions.Multiline);

            // ustawienie flagi, że regexpy zostały zaktualizowane
            regexUpdated = true;
        }

        // przetwarzanie regex
        private void ProcessRegex(RichTextBoxExtended richTextBoxExtended, string line, int lineStart, Regex regexp, Color color)
        {
            // jeśli regexp jest pusty, nie ma możliwości przetwarzania tekstu
            if (regexp == null)
            {
                return;
            }

            Match regMatch;

            for (regMatch = regexp.Match(line); regMatch.Success; regMatch = regMatch.NextMatch())
            {
                // przetwórz słowa
                int nStart = lineStart + regMatch.Index;
                int nLenght = regMatch.Length;
                richTextBoxExtended.SelectionStart = nStart;
                richTextBoxExtended.SelectionLength = nLenght;
                richTextBoxExtended.SelectionColor = color;
            }
        }

        // przetwarzanie linii
        private void ProcessLine(RichTextBoxExtended richTextBoxExtended, string line, int lineStart)
        {
            // coś
            int nPosition = richTextBoxExtended.SelectionStart;
            richTextBoxExtended.SelectionStart = lineStart;
            richTextBoxExtended.SelectionLength = line.Length;
            richTextBoxExtended.SelectionColor = Color.Black;

            // przetwarzanie słów kluczowych
            ProcessRegex(richTextBoxExtended, line, lineStart, keywordsRegexp, richTextBoxExtended.keywordsColor);

            ProcessRegex(richTextBoxExtended, line, lineStart, quotesRegexp, richTextBoxExtended.stringsColor);

            ProcessRegex(richTextBoxExtended, line, lineStart, numbersRegexp, richTextBoxExtended.numbersColor);

            // przetwarzanie komentarzy
            if (richTextBoxExtended.CommentsChars.Count > 0)
            {
                ProcessRegex(richTextBoxExtended, line, lineStart, commentsRegexp, richTextBoxExtended.commentsColor);
            }

            richTextBoxExtended.SelectionStart = nPosition;
            richTextBoxExtended.SelectionLength = 0;
            richTextBoxExtended.SelectionColor = Color.Black;
        }

        // przetwarzanie zaznaczania
        private void ProcessSelection(RichTextBoxExtended richTextBoxExtended, int selectionStart, int selectionLength)
        {
            int nPosition = selectionStart;

            richTextBoxExtended.SelectionStart = selectionStart;
            richTextBoxExtended.SelectionLength = selectionLength;
            string text = richTextBoxExtended.SelectedText;

            richTextBoxExtended.SelectionColor = Color.Black;

            // prztwarzanie słów kluczowych
            ProcessRegex(richTextBoxExtended, text, selectionStart, keywordsRegexp, richTextBoxExtended.keywordsColor);

            ProcessRegex(richTextBoxExtended, text, selectionStart, quotesRegexp, richTextBoxExtended.stringsColor);

            ProcessRegex(richTextBoxExtended, text, selectionStart, numbersRegexp, richTextBoxExtended.numbersColor);

            // przetwarzanie komentarzy
            if (richTextBoxExtended.commentsCharList.Count > 0)
            {
                ProcessRegex(richTextBoxExtended, text, selectionStart, commentsRegexp, richTextBoxExtended.commentsColor);
            }

            richTextBoxExtended.SelectionStart = nPosition;
            richTextBoxExtended.SelectionLength = 0;
            richTextBoxExtended.SelectionColor = Color.Black;
        }

        // przetwarzanie całości
        public void ProcessAllLines(RichTextBoxExtended richTextBoxExtended)
        {
            int nPosition = richTextBoxExtended.SelectionStart;
            richTextBoxExtended.SelectionStart = 0;
            richTextBoxExtended.SelectionLength = richTextBoxExtended.Text.Length;
            richTextBoxExtended.SelectionColor = Color.Black;

            // przetwarzanie słów kluczowych
            ProcessRegex(richTextBoxExtended, richTextBoxExtended.Text, 0, keywordsRegexp, richTextBoxExtended.keywordsColor);

            ProcessRegex(richTextBoxExtended, richTextBoxExtended.Text, 0, quotesRegexp, richTextBoxExtended.stringsColor);

            ProcessRegex(richTextBoxExtended, richTextBoxExtended.Text, 0, numbersRegexp, richTextBoxExtended.numbersColor);

            // przetwarzanie komentarzy
            if (richTextBoxExtended.commentsCharList.Count > 0)
            {
                ProcessRegex(richTextBoxExtended, richTextBoxExtended.Text, 0, commentsRegexp, richTextBoxExtended.commentsColor);
            }
            richTextBoxExtended.SelectionStart = nPosition;
            richTextBoxExtended.SelectionLength = 0;
            richTextBoxExtended.SelectionColor = Color.Black;
        }


    }
}
